'''
Created on Mar 25, 2013

@author: Petko
'''
from sent.model.entities import EntityWithUUID, EntBase
from sqlalchemy.schema import Column, ForeignKey
from sqlalchemy.types import BINARY, String, DateTime, Integer, Boolean, Unicode
from uuid import UUID
import uuid
from sqlalchemy.orm import relationship
from sententialyzer.settings import DEBUG

class OpinionEvaluations():
    
    NEGATIVE=1
    NEUTRAL=2
    POSITIVE=3
    
    STRING_TO_EVAL = {'negative' : NEGATIVE, 'neutral' : NEUTRAL, 'positive' : POSITIVE}
    
    EVAL_TO_SHORT_STRING = {NEGATIVE: "-", NEUTRAL: "=", POSITIVE: "+"}


class OpinionState():
    '''
    Creations and updates require locking and manipulating many other opinions in the current base opinion,
    so we do these operations at once for each base opinion. So until the pending operations are processed we
    need to know what operation is being applied on each opinion (its state)
                     ___________
                    V          |        
    INSERTED -> NORMAL -> WAITING_UPDATE-----v
                   |______________________> WAITING_DELETE
                         
    '''
    NORMAL=0
    INSERTED=1
    WAITING_UPDATE=2
    WAITING_DELETE=3
    
    STATE_TO_SHORT_STRING = {NORMAL: "n", INSERTED: "i", WAITING_UPDATE: "wu", WAITING_DELETE: "wd"}

class PendingUpdateState():
    IDLE=0
    ACTIVE=1

class Opinion(EntityWithUUID, EntBase):
    '''
    classdocs
    '''

    __tablename__ = 'Opinion'
    id = Column(BINARY, name='op_id', primary_key=True)
    base_op_id = Column(BINARY)
    creation_time = Column(DateTime)
    negative_attention = Column(Integer)
    positive_attention = Column(Integer)
    evaluation = Column(Integer)
    prev_eval = Column(Integer)
    creator_id = Column(BINARY, ForeignKey('User.id'))
    parent_id = Column(BINARY)
    default_perm = Column(String)
    has_content = Column(Boolean)
    op_state = Column(Integer, name='state',)
    
    nested_set_left = Column(Integer)
    nested_set_right = Column(Integer)
    tree_depth = Column(Integer)
    
#    num_content_subops = Column(Integer)
#    num_positive_subops = Column(Integer)
#    num_neutral_subops = Column(Integer)
#    num_negative_subops = Column(Integer)

    creator = relationship("User", innerjoin=True, lazy='noload')
    
    textData = ""
    external_data = ""
    title = ""
    subOpinions = None
    #totalSubopinions = -1
    
    def __repr__(self):
        return "<Opinion id=%s parent=%s base=%s p=%d n=%d e%s>" % (str(self.getUUID()), str(self.getParentUUID()), str(self.getBaseUUID()), 
                                                                self.positive_attention, self.negative_attention, 
                                                                OpinionEvaluations.EVAL_TO_SHORT_STRING[self.evaluation])
    
    def setCreatorIdString(self, creatorIdStr):
        uuid = UUID(creatorIdStr)
        self.creator_id = uuid.bytes
    
    def getCreatorUUID(self):
        return uuid.UUID(bytes=self.creator_id)
    
    def setParentIdStr(self, parentIdStr):
        uuid = UUID(parentIdStr)
        self.parent_id = uuid.bytes
        
    def getParentUUID(self):
        return uuid.UUID(bytes=self.parent_id)
    
    def getBaseUUID(self):
        return uuid.UUID(bytes=self.base_op_id)
    
    def getTotalSubopinions(self):
        return (self.nested_set_right - self.nested_set_left - 1) / 2
    
    def containsDefaultScope(self, scopeStr):
        strDefPerm = str(self.default_perm)
        return strDefPerm.count(scopeStr)
    
    def isParentOrSameAs(self, op):
        if isinstance(op, Opinion):
            
            #is it equal opinion
            if self.id == op.id:
                return True
            
            if self.base_op_id != op.base_op_id:
                return False
            
            #is it a parent
            return self.nested_set_left < op.nested_set_left and self.nested_set_right > op.nested_set_right
        else:
            return False
         
    def toPrimitiveDict(self):
        if DEBUG:
            result = EntityWithUUID.toPrimitiveDict(self)
            result.pop('parent_id', None)
            result['base_op_id'] = str(self.getBaseUUID())
            result.pop('creator_id', None)
        else:
            result = {}
        
        #result['parent_id'] = str(uuid.UUID(bytes=self.parent_id))
        #result['base_op_id'] = str(uuid.UUID(bytes=self.base_op_id))
        #result['creator_id'] = str(uuid.UUID(bytes=self.creator_id))
        result['id'] = str(self.getUUID())
        result['parent'] = str(self.getParentUUID())
        
        result['text'] = self.textData
        result['title'] = self.title
        result['external_data'] = self.external_data
        result['eval'] = OpinionEvaluations.EVAL_TO_SHORT_STRING[self.evaluation]
        
        result['total'] = self.getTotalSubopinions()
        result['negative'] = self.negative_attention
        result['positive'] = self.positive_attention
        result['created'] = self.creation_time.strftime("%Y-%m-%d %H:%M:%S")
        
#        result['num_content_subops'] = self.num_content_subops
#        result['num_positive_subops'] = self.num_positive_subops
#        result['num_neutral_subops'] = self.num_neutral_subops
#        result['num_negative_subops'] = self.num_negative_subops
    
        result['has_content'] = self.has_content
        
        result['state'] = OpinionState.STATE_TO_SHORT_STRING[self.op_state]
        
        if self.op_state == OpinionState.WAITING_UPDATE:
            result['prev_eval'] = OpinionEvaluations.EVAL_TO_SHORT_STRING[self.prev_eval]
        
        if self.creator:
            result['creator'] = self.creator.toPrimitiveDict()
        
        if self.subOpinions >= 0:
            dictList = []
            
            for subop in self.subOpinions:
                dictList.append(subop.toPrimitiveDict())
                
            result['sub_opinions'] = dictList
            
            
        return result
    
class TextStorage(EntityWithUUID, EntBase):
    __tablename__ = 'TextStorage'
    
    id = Column(BINARY, primary_key=True)
    title = Column(Unicode)
    content = Column(Unicode)
    external_data = Column(Unicode)

class PendingUpdateDeletes(EntityWithUUID, EntBase):
    __tablename__ = 'Pending_Insert_Deletes'

    id = Column(BINARY, name='base_op_id', primary_key=True)
    state = Column(Integer)
    
class ViewEnt(EntityWithUUID, EntBase):
    __tablename__ = 'View'
    id = Column(BINARY, primary_key=True)
    external_id = Column(Unicode)
    default_perm = Column(String)
    
    def toPrimitiveDict(self):
        result = EntityWithUUID.toPrimitiveDict(self)
        result.pop('default_perm')
        
    def containsDefaultScope(self, scopeStr):
        strDefPerm = str(self.default_perm)
        return strDefPerm.count(scopeStr)
    
class ViewOpinion(EntBase):
    __tablename__ = 'View_Opinions'
    opinion_id = Column(BINARY, primary_key=True)
    view_id = Column(BINARY, primary_key=True)
    